use anyhow::Result;
use chrono::Utc;
use hmac::{Hmac, Mac};
use reqwest::Client;
use serde::{Deserialize, Serialize};
use serde_json::json;
use sha2::{Sha256, Digest};
use std::time::{SystemTime, UNIX_EPOCH};

#[derive(Debug, Serialize, Deserialize)]
struct TranslateResponse {
    Response: TranslateResult,
}

#[derive(Debug, Serialize, Deserialize)]
struct TranslateResult {
    TargetText: String,
    RequestId: String,
}

#[derive(Clone)]
pub struct Translator {
    client: Client,
    secret_id: String,
    secret_key: String,
}

impl Translator {
    pub fn new(secret_id: String, secret_key: String) -> Self {
        Self {
            client: Client::new(),
            secret_id,
            secret_key,
        }
    }

    fn sign(&self, key: &[u8], msg: &str) -> Vec<u8> {
        let mut mac = Hmac::<Sha256>::new_from_slice(key).unwrap();
        mac.update(msg.as_bytes());
        mac.finalize().into_bytes().to_vec()
    }

    pub async fn translate_text(&self, text: &str) -> Result<String> {
        // 保持向后兼容，默认英译中
        self.translate_text_with_langs(text, "en", "zh").await
    }

    pub async fn translate_text_with_langs(&self, text: &str, source_lang: &str, target_lang: &str) -> Result<String> {
        let service = "tmt";
        let host = "tmt.tencentcloudapi.com";
        let region = "ap-guangzhou";
        let version = "2018-03-21";
        let action = "TextTranslate";
        let payload = json!({
            "SourceText": text,
            "Source": source_lang,
            "Target": target_lang,
            "ProjectId": 0
        });
        let payload_str = payload.to_string();

        let algorithm = "TC3-HMAC-SHA256";
        let timestamp = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_secs();
        let date = Utc::now().format("%Y-%m-%d").to_string();

        // 步骤1：拼接规范请求串
        let http_request_method = "POST";
        let canonical_uri = "/";
        let canonical_querystring = "";
        let ct = "application/json; charset=utf-8";
        let canonical_headers = format!(
            "content-type:{}\nhost:{}\nx-tc-action:{}\n",
            ct, host, action.to_lowercase()
        );
        let signed_headers = "content-type;host;x-tc-action";
        let hashed_request_payload = hex::encode(Sha256::digest(payload_str.as_bytes()));
        
        let canonical_request = format!(
            "{}\n{}\n{}\n{}\n{}\n{}",
            http_request_method,
            canonical_uri,
            canonical_querystring,
            canonical_headers,
            signed_headers,
            hashed_request_payload
        );

        // 步骤2：拼接待签名字符串
        let credential_scope = format!("{}/{}/tc3_request", date, service);
        let hashed_canonical_request = hex::encode(Sha256::digest(canonical_request.as_bytes()));
        let string_to_sign = format!(
            "{}\n{}\n{}\n{}",
            algorithm, timestamp, credential_scope, hashed_canonical_request
        );

        // 步骤3：计算签名
        let secret_date = self.sign(format!("TC3{}", self.secret_key).as_bytes(), &date);
        let secret_service = self.sign(&secret_date, service);
        let secret_signing = self.sign(&secret_service, "tc3_request");
        let signature = hex::encode(self.sign(&secret_signing, &string_to_sign));

        // 步骤4：拼接 Authorization
        let authorization = format!(
            "{} Credential={}/{}, SignedHeaders={}, Signature={}",
            algorithm, self.secret_id, credential_scope, signed_headers, signature
        );

        // 步骤5：构造并发起请求
        let response = self.client
            .post(format!("https://{}", host))
            .header("Authorization", authorization)
            .header("Content-Type", ct)
            .header("Host", host)
            .header("X-TC-Action", action)
            .header("X-TC-Timestamp", timestamp.to_string())
            .header("X-TC-Version", version)
            .header("X-TC-Region", region)
            .body(payload_str)
            .send()
            .await?;

        let translate_response: TranslateResponse = response.json().await?;
        Ok(translate_response.Response.TargetText)
    }
}
